#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>

#define UNIX_DOMAIN "/tmp/haha"

#define UNIXDOMAIN_LOG_ERR(format, args...) fprintf(stderr, "[%s][%s][%d]"format, __FILE__, __FUNCTION__, __LINE__, ##args);

#define BUFFER_SIZE 1000
int test_new_socket(int accept_fd)
{
    int ret = 0;
    char buf[BUFFER_SIZE] = {'a','b','c','d'};
    int byte = 0;
    //printf(">");
    //scanf("%s", buf);
    byte = write(accept_fd, buf, strlen(buf)+1 );
    if (byte <= 0) {
        UNIXDOMAIN_LOG_ERR("write failed:%s\n", strerror(errno));
        ret = -1;
        goto out;
    }
    printf("send %s\n", buf);
    if ( (ret = read(accept_fd, buf, BUFFER_SIZE-1 )) < 0) {
        UNIXDOMAIN_LOG_ERR("read failed:%s\n", strerror(errno));
        ret = -1;
        goto out;
    }
    buf[ret] = '\0';
    printf("recv:%s\n", buf);
    sleep(1);
out:
    return ret;
}

int create_unixdomain_server()
{
    int ret = 0;  
    int sockfd = 0;
    struct sockaddr_un server_addr, client_addr;
    socklen_t client_len = 0;
    if ( (sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0 ) {
        UNIXDOMAIN_LOG_ERR("socket failed, reason:%s\n", strerror(errno));
        ret = -1;
        goto out;
    }
    server_addr.sun_family = AF_UNIX;
    strncpy(server_addr.sun_path, UNIX_DOMAIN, sizeof(server_addr.sun_path)-1);
    unlink(UNIX_DOMAIN);

    if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        UNIXDOMAIN_LOG_ERR("bind failed:%s\n", strerror(errno));
        ret = -1;
        goto out;
    }
    if (listen(sockfd, 5) < 0) {
        UNIXDOMAIN_LOG_ERR("listen error:%s", strerror(errno));
        ret = -1;
        goto out;
    }
    while(1) {
        client_len = sizeof(client_addr);
        int accept_fd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);
        if (accept_fd < 0) {
            UNIXDOMAIN_LOG_ERR("accept failed:%s\n", strerror(errno));
            continue;
        }
        
        test_new_socket(accept_fd);
        close(accept_fd);
    }
      
out:
    if (sockfd) {
        close(sockfd);
    }
    unlink(UNIX_DOMAIN);
    return ret;
}

#define MESG_BUFFER_SIZE 1000
int create_unixdomain_client()
{
    int ret = 0;
    char mesg[MESG_BUFFER_SIZE] = {0};
    int sockfd = 0;
    
    struct sockaddr_un server_addr;
    server_addr.sun_family = AF_UNIX;
    strncpy(server_addr.sun_path, UNIX_DOMAIN, sizeof(server_addr.sun_path)-1);
    if ( (sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) <0) {
        UNIXDOMAIN_LOG_ERR("socket failed:%s\n", strerror(errno));
        ret = -1;
        goto out;
    }
    if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        UNIXDOMAIN_LOG_ERR("connect failed:%s\n", strerror(errno));
        ret = -1;
        goto out;
    }
    
    if ( (ret = read(sockfd, mesg, MESG_BUFFER_SIZE-1)) < 0) {
        UNIXDOMAIN_LOG_ERR("read failed:%s\n", strerror(errno));
        ret = -1;
        goto out;
    }
    mesg[ret] = '\0';
    printf("recv from server:%s\n", mesg);
    
    if (write(sockfd, mesg, strlen(mesg)) < 0) {
        UNIXDOMAIN_LOG_ERR("write failed:%s\n", strerror(errno));
        ret = -1;
        goto out;
    }
    printf("send back:%s\n", mesg);
out:
    if (sockfd)
        close(sockfd);
    return 0;      
}

int main(int argc, char** argv)
{
    if (argc == 2 && strncmp(argv[1], "-c", strlen("-c")) == 0) {
        fprintf(stdout, "start unix domain client\n");
        create_unixdomain_client();
    }
    else {
        fprintf(stdout, "start unix domain server\n");
        create_unixdomain_server();
    }
    return 0;
}